#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import os
import time
import random
import hashlib
import base64
import math
from getpass import getpass

# ==============================================
# XG加密工具核心模块
# 功能：7种加密算法 + 动态密钥可视化
# 版本：v2.2 (跨平台)
# ==============================================

# 全局配置
OS_TYPE = os.name
IS_TERMUX = 'com.termux' in os.environ.get('PREFIX', '')

# 颜色定义
class Colors:
    RED = '\033[1;31m'
    GREEN = '\033[1;32m'
    YELLOW = '\033[1;33m'
    BLUE = '\033[1;34m'
    MAGENTA = '\033[1;35m'
    CYAN = '\033[1;36m'
    WHITE = '\033[1;37m'
    RESET = '\033[0m'

    @staticmethod
    def rgb(r, g, b):
        return f"\033[38;2;{r};{g};{b}m" if OS_TYPE != 'nt' else ''

# 动态密钥网格系统
class DynamicGrid:
    def __init__(self, mode):
        self.mode = mode  # 4=混合密钥 7=数字密钥
        self.fps = 3      # 刷新率(帧/秒)
        self.last_update = 0
        self.colors = Colors()
        
        # 自动调整网格大小
        self.get_terminal_size()
        self.init_grid()
        
        # 终端控制序列
        self.HIDE_CURSOR = "\033[?25l"
        self.SHOW_CURSOR = "\033[?25h"
        self.CLEAR_LINE = "\033[2K"
        self.SAVE_SCREEN = "\033[?1049h" if not IS_TERMUX else ""
        self.RESTORE_SCREEN = "\033[?1049l" if not IS_TERMUX else ""

    def get_terminal_size(self):
        try:
            if OS_TYPE == 'nt':
                from ctypes import windll, create_string_buffer
                h = windll.kernel32.GetStdHandle(-12)
                csbi = create_string_buffer(22)
                windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
                cols = csbi[10] - csbi[6] + 1
                rows = csbi[12] - csbi[8] + 1
            else:
                import fcntl, termios, struct
                h, w = 24, 80
                try:
                    h, w = struct.unpack('hh', fcntl.ioctl(0, termios.TIOCGWINSZ, b'1234'))
                except:
                    pass
                cols, rows = w, h
            
            self.rows = max(4, min(8, rows - 8))
            self.cols = max(6, min(12, (cols - 4) // 6))
        except:
            self.rows, self.cols = (6, 8)  # 默认大小

    def init_grid(self):
        self.grid = []
        for _ in range(self.rows):
            row = []
            for _ in range(self.cols):
                row.append(self.generate_char())
            self.grid.append(row)
        
        # 存储字符位置
        self.char_positions = {}
        self.update_positions()

    def generate_char(self):
        if self.mode == 4:  # 混合模式
            char_type = random.randint(0, 2)
            if char_type == 0:
                return str(random.randint(0, 9))
            elif char_type == 1:
                return chr(random.randint(97, 122))  # a-z
            else:
                return chr(random.randint(65, 90))    # A-Z
        else:  # 数字模式
            return str(random.randint(0, 9))

    def update_positions(self):
        """计算每个字符的屏幕坐标"""
        start_row = 4  # 标题占4行
        for i in range(self.rows):
            for j in range(self.cols):
                # 每个字符占据6列宽(考虑边框)
                self.char_positions[(i, j)] = (
                    start_row + i * 2,
                    3 + j * 6
                )

    def update_grid(self):
        """按概率更新网格字符"""
        current_time = time.time()
        if current_time - self.last_update < 1.0 / self.fps:
            return
        
        self.last_update = current_time
        changes = 0
        
        for i in range(self.rows):
            for j in range(self.cols):
                # 基于正弦波的变化概率
                change_prob = abs(math.sin(
                    current_time * 2 + i/self.rows + j/self.cols
                )) * 0.6
                
                if random.random() < change_prob:
                    self.grid[i][j] = self.generate_char()
                    self.update_char(i, j)
                    changes += 1
        
        # 强制至少更新1个字符
        if changes == 0:
            i, j = random.randint(0, self.rows-1), random.randint(0, self.cols-1)
            self.grid[i][j] = self.generate_char()
            self.update_char(i, j)

    def update_char(self, i, j):
        """更新单个字符到终端"""
        if (i, j) not in self.char_positions:
            return
            
        row, col = self.char_positions[(i, j)]
        char = self.grid[i][j]
        
        # 随机颜色效果
        if self.mode == 4:  # 混合模式
            color = random.choice([
                self.colors.RED, self.colors.GREEN, self.colors.YELLOW,
                self.colors.BLUE, self.colors.MAGENTA, self.colors.CYAN
            ])
        else:  # 数字模式
            r = random.randint(100, 255)
            color = Colors.rgb(r, r//2, 0) if OS_TYPE != 'nt' else self.colors.YELLOW
        
        # ANSI定位输出
        sys.stdout.write(f"\033[{row};{col}H{color}{char}{self.colors.RESET}")
        sys.stdout.flush()

    def draw_borders(self):
        """绘制网格边框"""
        sys.stdout.write(self.SAVE_SCREEN)
        sys.stdout.write("\033[2J\033[H")  # 清屏并移动光标到左上角
        
        # 标题
        title = "动态混合密钥" if self.mode == 4 else "动态数字密钥"
        sys.stdout.write(f"\n  {self.colors.CYAN}╔{'═'*(self.cols*6-1)}╗{self.colors.RESET}\n")
        sys.stdout.write(f"  {self.colors.CYAN}║{self.colors.WHITE}{title.center(self.cols*6-1)}{self.colors.CYAN}║{self.colors.RESET}\n")
        sys.stdout.write(f"  ╠{'═'*5}╬{'═'*5}╬{'═'*5}╣\n".replace('═', f"{self.colors.CYAN}═{self.colors.RESET}"))

        # 初始绘制所有字符
        for i in range(self.rows):
            for j in range(self.cols):
                self.update_char(i, j)
            if i < self.rows - 1:
                sys.stdout.write(f"  ╠{'═'*5}╬{'═'*5}╬{'═'*5}╣\n".replace('═', f"{self.colors.CYAN}═{self.colors.RESET}"))
        
        # 底部边框
        sys.stdout.write(f"  ╚{'═'*5}╩{'═'*5}╩{'═'*5}╝\n".replace('═', f"{self.colors.CYAN}═{self.colors.RESET}"))
        sys.stdout.write(f"  {self.colors.GREEN}刷新率: {self.fps}FPS | 按Ctrl+C停止{self.colors.RESET}\n")
        sys.stdout.flush()

    def run(self):
        try:
            sys.stdout.write(self.HIDE_CURSOR)
            self.draw_borders()
            
            while True:
                self.update_grid()
                time.sleep(0.01)  # 降低CPU占用
                
        except KeyboardInterrupt:
            sys.stdout.write(f"\n{self.colors.RED}[!] 已停止密钥生成{self.colors.RESET}\n")
        finally:
            sys.stdout.write(self.SHOW_CURSOR + self.RESTORE_SCREEN)
            sys.stdout.flush()

# ================= 加密算法 =================

def icloud_encrypt(text):
    """iCloud风格密钥派生"""
    salt = os.urandom(32)
    iterations = 100000
    key = hashlib.pbkdf2_hmac('sha256', text.encode(), salt, iterations)
    return base64.b64encode(salt + key).decode()

def hash_encrypt(text, iterations=1000):
    """多层哈希加密"""
    salted = f"{text}XG_SALT_{len(text)}"
    for _ in range(iterations):
        salted = hashlib.sha512(salted.encode()).hexdigest()
    return salted

def monkey_algorithm(text):
    """猴子乱序加密"""
    chars = list(text)
    for _ in range(len(chars) * 2):
        i, j = random.sample(range(len(chars)), 2)
        chars[i], chars[j] = chars[j], chars[i]
    return ''.join(chars) + ''.join(random.choices('0123456789ABCDEF', k=8))

def caesar_cipher(text, shift=None):
    """凯撒密码增强版"""
    if shift is None:
        shift = random.randint(1, 25)
    
    result = []
    for char in text:
        if char.isupper():
            result.append(chr((ord(char) + shift - 65) % 26 + 65))
        elif char.islower():
            result.append(chr((ord(char) + shift - 97) % 26 + 97))
        elif char.isdigit():
            result.append(str((int(char) + shift) % 10))
        else:
            result.append(char)
    return ''.join(result), shift

def usb_dongle_emulate():
    """加密狗模拟(仅PC)"""
    if OS_TYPE == 'nt':
        from ctypes import windll
        volume_serial = windll.kernel32.GetVolumeInformationA("C:\\", None, 0, None, None, None, None, 0)
        return hashlib.sha256(str(volume_serial).encode()).hexdigest()
    else:
        return hashlib.sha256(os.uname().version.encode()).hexdigest()

# ================= 主程序 =================

def main():
    if len(sys.argv) < 2:
        print(f"{Colors.RED}[!] 请通过主菜单调用本程序{Colors.RESET}")
        return

    mode = int(sys.argv[1])
    
    try:
        if mode in (4, 7):
            DynamicGrid(mode).run()
            
        elif mode in (1, 2, 3, 6):
            print(f"\n{Colors.CYAN}=== {['iCloud加密', '哈希加密', '猴子算法', '凯撒加密'][mode-1]} ==={Colors.RESET}")
            
            if mode == 6:  # 凯撒加密特殊处理
                text = input("输入文本: ")
                shift = input("移位值(留空随机): ")
                shift = int(shift) if shift.isdigit() else None
                result, used_shift = caesar_cipher(text, shift)
                print(f"加密结果: {Colors.GREEN}{result}{Colors.RESET}")
                print(f"使用移位: {used_shift}")
            else:
                text = getpass("输入内容(安全输入): ")
                funcs = [icloud_encrypt, hash_encrypt, monkey_algorithm]
                print(f"加密结果:\n{Colors.YELLOW}{funcs[mode-1](text)}{Colors.RESET}")
            
            input("\n按回车键返回...")
            
        elif mode == 5:
            print(f"\n{Colors.BLUE}=== 加密狗模拟 ==={Colors.RESET}")
            print(f"设备指纹: {Colors.MAGENTA}{usb_dongle_emulate()}{Colors.RESET}")
            input("\n按回车键返回...")
            
    except Exception as e:
        print(f"{Colors.RED}[!] 错误: {e}{Colors.RESET}")
        if mode not in (4, 7):
            input("按回车键返回...")

if __name__ == "__main__":
    # Windows颜色支持
    if OS_TYPE == 'nt':
        try:
            import colorama
            colorama.init()
        except:
            pass
    
    main()